﻿module BrowserWindow

open System
open System.Threading
open HttpInterfaces
open HtmlParser
open UriParsing
open Dom
open DocumentHost
open DocumentFactory
open HttpInterfaces
open Uris

(*
    This one is persistent, as opposed to DocumentWindow which is instantiated for each document
    Responsible for persistent data like history
*)


type BrowserWindow(renderCallback:DomChangedCallback, loader:IResourceLoader, log : (string->unit), navigate : (HttpRequest->Async<ResponseOption>)) =  
    let _renderCallback = renderCallback
    let _log = log
    (* only one document request pr window running at a time, so we cancel previous if overlap *)
    let mutable _cancelNavigate = new CancellationTokenSource()

    interface IDocumentHost with
        
        member this.navigate(uri:HttpUrl) = 
            let request = GetRequest(uri)
            this.requestDocument(request)

        member this.submit (uri:HttpUrl, httpMethod:string, encoding:string, data:(string*string) list) =
            let pairs = [for (key, value) in data -> urlEncode(key) + "=" + urlEncode(value)]
            let data = String.Join("&", pairs)
            let request =
                match httpMethod.ToUpperInvariant() with
                | "GET" ->
                    let queryString = "?" + data
                    let uri = {uri with queryString = queryString }                
                    GetRequest(uri)
                | "POST" ->
                    PostRequest(uri, data)
            this.requestDocument(request)

        member this.log(txt) =
            log(txt)

    member this.loadDocument(uri:HttpUrl, html:string) =        
        let doc = createDocument renderCallback uri loader this
        do parseHtml doc html  
        doc.redraw()      

    member this.requestDocument (request:HttpRequest) = 
        let request1 =
            async {
                if request.url.scheme<>"http" then failwith "Scheme not supported"                    
                let! res = navigate request 
                match res with
                | Failure(msg) -> do
                    Windows.MessageBox.Show("Navigation failure: " + msg) |> ignore
                | Success(response, actualUri) ->
                    match response.body with
                        | TextBody txt ->
                            this.loadDocument(actualUri, txt) 
                        |  _ -> ()
            }  
        do _cancelNavigate.Cancel ()
        do _cancelNavigate <- new CancellationTokenSource()
        Async.Start(request1, _cancelNavigate.Token)


    // url from address bar, so not relative
    member this.navigateUrl(url:string) = 
       let uri = parseUrl url None
       (this :> IDocumentHost).navigate uri


       
